package foundation;

import java.io.InputStream;
import java.net.Socket;
import java.util.Observable;
import java.util.Observer;

public class FDataStreamReader extends Observable implements Runnable{
	private final int RECONNECT_DELAY = 5000;
	private String address;
	private int port;
	private boolean firstError = true;
	private FStatusNotifier statusNotifier = new FStatusNotifier();
	private String[] okText = {"OK","Data connection ok."};
	private String[] errText = {"NC","No data connection to car. Check error log."};
	
	private enum State
	{
	    readingFirstLine, readingSecondLine, readingOD; 
	}
	
	public FDataStreamReader(String address, int port) {
		this.address = address;
		this.port = port;
	}
	
	public void addStatusObserver(Observer obs) {
		statusNotifier.addObserver(obs);
	}
	
	public void deleteStatusObserver(Observer obs) {
		statusNotifier.deleteObserver(obs);
	}
	
	@Override
	public void run() {
		Socket socket = null;
		InputStream istream = null;
		while (true) {
			try {
				socket = new Socket(address,port);
				socket.setSoTimeout(5000);
				istream = socket.getInputStream();
				int readByte;
				byte[] readOD = new byte[2048];
				String line = "";
				int bytesRead = 0;
				State state = State.readingFirstLine;
				firstError = true;
				statusNotifier.setChanged();
				statusNotifier.notifyObservers(okText);

				while((readByte = istream.read()) != -1) {
					switch (state) {
					case readingFirstLine :
						if (readByte != 10) {
							line += (char) readByte;
						} else {
							if (line.equalsIgnoreCase("OD Data")) {
								state = State.readingSecondLine;
							}
							line = "";
						}
						break;
					case readingSecondLine :
						if (readByte != 10) {
							line += (char) readByte;
						} else {
							line = "";
							state = State.readingOD;
						}
						break;
					case readingOD :
						readOD[bytesRead++] = (byte) readByte;

						if (bytesRead == 2048) {
							bytesRead = 0;
							setChanged();
							notifyObservers(readOD);
							state = State.readingFirstLine;
						}

						break;
					}
				}
				istream.close();
				socket.close();
				if (firstError) {
					String error = "Data connection to car lost. Using address" 
						+ "=" + address + " and port=" + port + ". Retrying " 
						+ "connection every " + RECONNECT_DELAY/1000 + "s";
					setChanged();
					notifyObservers(error);
					statusNotifier.setChanged();
					statusNotifier.notifyObservers(errText);
					firstError = false;
				}
				
			} catch (Exception e) {
				try {
					istream.close();
				} catch (Exception e1) {}
				try {
					socket.close();
				} catch (Exception e1) {}
				
				if (firstError) {
					e.printStackTrace();
					
					String error = "No data connection to car. Using address" 
						+ "=" + address + " and port=" + port + ". Retrying " 
						+ "connection every " + RECONNECT_DELAY/1000 + "s";
					setChanged();
					notifyObservers(error);
					statusNotifier.setChanged();
					statusNotifier.notifyObservers(errText);
					firstError = false;
				}
			}

			try {
				Thread.sleep(RECONNECT_DELAY);
			} catch (InterruptedException e) {}
		}
	}
	
	public int convertNumber(String number, int format) {
		return 0;
	}
}
